﻿using OpenTK;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OpenTKApp
{
    public class Camera
    {
        // Those vectors are directions pointing outwards from the camera to define how it rotated
        private Vector3 _front = -Vector3.UnitX;

        private Vector3 _up = Vector3.UnitZ;

        private Vector3 _right = Vector3.UnitY;


        // The field of view of the camera (radians)
        private float _fov = MathHelper.PiOver4;

        public Camera(Vector3 position, float aspectRatio)
        {
            Position = position;
            AspectRatio = aspectRatio;
            _front = Vector3.Normalize(-Position);
            _right = Vector3.Normalize(Vector3.Cross(_front, _up));
            _up = Vector3.Normalize(Vector3.Cross(_right, _front));
        }

        // The position of the camera
        public Vector3 Position { get; set; }

        // This is simply the aspect ratio of the viewport, used for the projection matrix
        public float AspectRatio { private get; set; }

        public Vector3 Front => _front;

        public Vector3 Up => _up;

        public Vector3 Right => _right;

        public float Fov
        {
            get => MathHelper.RadiansToDegrees(_fov);
            set
            {
                var angle = Clamp(value, 1f, 45f);
                _fov = MathHelper.DegreesToRadians(angle);
            }
        }

        // Get the view matrix using the amazing LookAt function described more in depth on the web tutorials
        public Matrix4 GetViewMatrix()
        {
            return Matrix4.LookAt(Position, Position + _front, _up);
        }

        // Get the projection matrix using the same method we have used up until this point
        public Matrix4 GetProjectionMatrix()
        {
            return Matrix4.CreatePerspectiveFieldOfView(_fov, AspectRatio, 0.01f, 100f);
        }


        public void PitchView(float X_Angle, float Y_Angle)
        {
            Matrix3 RotateMatrix = Matrix3.CreateFromAxisAngle(_up, X_Angle);
            Position = Vector3.Transform(Position, RotateMatrix);
            _front = Vector3.Normalize(-Position);

            _right = Vector3.Normalize(Vector3.Cross(_front, _up));

            RotateMatrix = Matrix3.CreateFromAxisAngle(_right, Y_Angle);
            Position = Vector3.Transform(Position, RotateMatrix);
            _front = Vector3.Normalize(-Position);

            _up = Vector3.Normalize(Vector3.Cross(_right, _front));

        }

        float Clamp(float val, float min, float max)
        {
            return val > max ? max : val < min ? min : val;
        }
    }
}
